package com.lottery.game.runner.v2;

import com.google.common.collect.Lists;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lottery.game.common.constants.GameConstants;
import com.lottery.game.common.utils.DateUtils;
import com.lottery.game.common.utils.StringUtil;
import com.lottery.game.common.utils.UUIDUtils;
import com.lottery.game.core.configuration.SftpUtils;
import com.lottery.game.core.modules.entity.user.ChatRecord;
import com.lottery.game.core.modules.entity.user.UserRankPojo;
import com.lottery.game.core.modules.service.app.ChatRecordService;
import com.lottery.game.core.modules.service.app.OnlineAppContext;
import com.lottery.game.core.modules.service.app.OperationalSetService;
import com.lottery.game.core.modules.service.app.UserRankService;
import com.lottery.game.core.modules.service.app.WebSocketService;
import com.lottery.game.core.modules.service.app.WebsocketMessageService;
import com.lottery.game.core.modules.service.game.SysDictService;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.extern.slf4j.Slf4j;

/**
 * 替代RobotSpeak
 *
 * @author Administrator
 *
 */
@Slf4j
@Component
public class RobotSpeakExecutor {

	@Autowired
	private OperationalSetService operationalSetService;

	@Autowired
	private ChatRecordService chatRecordService;

	@Autowired
	private WebSocketService webSocketService;

	@Autowired
	private WebsocketMessageService websocketMessageService;

	@Autowired
	private OnlineAppContext context;

	@Autowired
	private SysDictService sysDictService;

	@Autowired
	private UserRankService userRankService;
	/**
	 * 下注方案分割 正则
	 */
	private static final Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+|\\d+");

	private static final String RANDOM_AMOUNT_STRING = "随机金额";

	/**
	 * 机器人下注 默认随机时间ROLL值最小值
	 */
	private static final int ROBOT_BET_MIN_TIME = 20;
	/**
	 * 机器人下注 默认随机时间ROLL值最大值
	 */
	private static final int ROBOT_BET_MAX_TIME = 60;
	/**
	 * 机器人下注 默认几率
	 */
	private static final int ROBOT_BET_CHANCE = 50;
	/**
	 * 机器人随机下注时，每个规则下注的概率
	 */
	private static final int ROBOT_RANDOM_BET_CHANCE = 35;

	/**
	 * 执行发言
	 */
	@Async
	public void execute(String roomNumber, long startTime, long endTime, String gameQi) {
		List<Map<String, Object>> robotList = operationalSetService.queryRobotInfo(roomNumber);
		Map<String, Object> robotConf = operationalSetService.queryDictRobot();

		final Integer betChance = (robotConf.containsKey("betChance"))
				? Integer.valueOf((String) robotConf.get("betChance"))
				: ROBOT_BET_CHANCE;
		// 读取列表中机器人的信息
		if (!CollectionUtils.isEmpty(robotList)) {
			Random random = new Random();

			robotList.stream().forEach(robot -> {
				String robotName = null;
				try {
					int minTime = ROBOT_BET_MIN_TIME;
					int maxTime = ROBOT_BET_MAX_TIME;
					// 获取机器人信息
					if (robot.containsKey("minTime") && !StringUtils.isEmpty(robot.get("minTime"))) {
						minTime = Integer.valueOf((String) robot.get("minTime"));
					}
					if (robot.containsKey("maxTime") && !StringUtils.isEmpty(robot.get("minTime"))) {
						maxTime = Integer.valueOf((String) robot.get("maxTime"));
					}
					String robotIcon = (String) robot.get("robotIcon");
					robotName = (String) robot.get("robotName");
					String schemeId = (String) robot.get("schemeId");
					String userLv = (String) robot.get("userLv");
					String[] schemeIds = schemeId.split(",");
					int r = random.nextInt(schemeIds.length - 0 + 0) + 0;
					String robotBetScheme = operationalSetService.querySchemeId(schemeIds[r]);
					String itemMessage = createMessage(robotBetScheme, roomNumber, false);
					// 执行发言
					speak(startTime, robotName, robotIcon, itemMessage, roomNumber, maxTime, minTime, endTime, gameQi,
							betChance, robotBetScheme, userLv);
				} catch (Exception e) {
					log.debug(String.format("机器人{}发言异常，{}", robotName, e.getMessage()));
					e.printStackTrace();
				}
			});

		}
	}

	/**
	 * 根据下注方案 生成下注的推送内容
	 *
	 * @param robotBetScheme
	 * @param roomNumber
	 * @param isRandom       是否随机抽取其中几项下注
	 * @return
	 */
	private String createMessage(String robotBetScheme, String roomNumber, Boolean isRandom) {
		String itemMessage = "";
		if (!StringUtils.isEmpty(robotBetScheme)) {
			String[] betRules = robotBetScheme.split("\\s+");
			int amount = 0;
			// 多种下注也只能使用同等下注金额，所以只取第一项下注规则的金额
			StringBuilder sb = new StringBuilder();
			for (int k = 0; k < betRules.length; k++) {
				String[] betRule = pattern(betRules[k]);
				// TODO:待调整 生成金额 转换 switch
				if (betRule[1].equals("随机金额1") && k == 0) {
					amount = ThreadLocalRandom.current().nextInt(9) * 10 + 10;
				} else if (betRule[1].equals("随机金额2") && k == 0) {
					amount = ThreadLocalRandom.current().nextInt(80) * 10 + 100;
				} else if (betRule[1].equals("随机金额3") && k == 0) {
					amount = ThreadLocalRandom.current().nextInt(300) * 10 + 1000;
				} else if (betRule[1].equals("随机金额4") && k == 0) {
					amount = ThreadLocalRandom.current().nextInt(500) * 10 + 4000;
				} else if (k == 0) {
					amount = Integer.valueOf(betRule[1]);
				}
				if (isRandom && k == 0) {
					double randomParameter;
					if (amount <= 100) {
						amount = ThreadLocalRandom.current().nextInt(5) * 10 + 10;
					} else {
						randomParameter = ((10.0 + ThreadLocalRandom.current().nextInt(10)) / 100);
						amount = (int) (randomParameter * amount) / 10 * 10;
					}
				}
				// 赔率
				String plInfo = initpl(roomNumber, betRule[0]);
				if (k == 0) {
					// 彩种类型 、赔率、下注金额
					sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
				} else {
					if (!isRandom) {
						sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
					} else {
						// 通过校验判断是否下注
						if (ThreadLocalRandom.current().nextInt(100) < ROBOT_RANDOM_BET_CHANCE) {
							sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
						}
					}
				}
				/**
				 * TODO:待删除 itemMessage += betRule[0] + "," + plInfo + "," + amount; if (s == 0)
				 * { itemMessage += betRule[0] + "," + plinfo + "," + betRule[1]; } else { if (s
				 * > 10 && (s % 10 != 0)) { s = s / 10 * 10 + 10; } amount = s; // 大 、赔率、下注金额
				 * itemMessage += betRule[0] + "," + plinfo + "," + amount; }
				 */
			}
			itemMessage = sb.toString();
		}
		return StringUtil.isNotBlank(itemMessage) ? itemMessage.substring(0, itemMessage.length() - 1) : itemMessage;
	}

	public void speak(long startTime, String robotName, String robotIcon, String message, String roomNuber, int maxTime,
			int minTime, long endTime, String gameQi, int betChance, String robotBetScheme, String userLv) {
		// logger.debug(String.format("机器人【%s】下注",robotName));
		Random random = new Random();

		int s = random.nextInt(maxTime - minTime + 1) + minTime;
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				long expectTime = 0;
				long endTimeTmp = endTime;

				try {
					while (true) {
						// TODO：判断意义不明，待检查
						if (expectTime == 0 || expectTime <= System.currentTimeMillis()) {
							if (expectTime != 0) {

								sendMsgToRoom(robotName, robotIcon, message, roomNuber, gameQi,userLv);
								log.debug("机器人【{}】第一次下注成功", robotName);
								// 如果 二次下注概率大于1 则追加下注
								// 剩余时间小于10秒不再二次投注
								int r = ThreadLocalRandom.current().nextInt(100);
								log.debug("【{}】【{}】随机数：{}", gameQi, robotName, r);
								if (r < betChance && endTimeTmp > 10000) {
									// TODO:二次下注可重构下注信息message
									String reBetMessage = createMessage(robotBetScheme, roomNuber, true);
									Long l = endTimeTmp - 10000;
									int rebetTime = ThreadLocalRandom.current().nextInt(l.intValue());
									log.debug(String.format("机器人【{}】{}秒后第二次下注", robotName, (rebetTime + 1000) / 1000));
									TimeUnit.MILLISECONDS.sleep(rebetTime + 1000);

									sendMsgToRoom(robotName, robotIcon, reBetMessage, roomNuber, gameQi, userLv);
									log.debug("机器人【{}】第二次下注成功", robotName);
								} else {
									log.debug("机器人【{}】第二次下注判断未通过", robotName);
								}
								break;
							}
						}
						expectTime = startTime + s * 1000;
						endTimeTmp = endTime - s * 1000;
						log.debug("机器人【{}】{}秒后第一次下注", robotName, s);
						if (endTimeTmp < 0) {
							log.debug("机器人结束仍未发言");
							break;
						}
						TimeUnit.MILLISECONDS.sleep(1000 * s);
						// 判断有没有封盘如果有封盘那么也结束线程
						// TODO:封盘判断逻辑似乎错误,待删除
						long nowTime = System.currentTimeMillis();
						if (nowTime == endTime) {
							log.debug("机器人结束仍未发言");
							break;
						}
					}
				} catch (Exception e) {
					log.debug("机器人【{}】下注线程异常：{}", robotName, e.toString());
					e.printStackTrace();
				}
			}
		});
		thread.start();

	}

	/**
	 * 给所有的房间的人推送消息
	 *
	 * @param robotName
	 * @param robotIcon
	 * @param robotMessage
	 * @param roomNumber
	 */
	private void sendMsgToRoom(String robotName, String robotIcon, String robotMessage, String roomNumber,
			String gameQi, String userLv) {
		String robotIconUrl = sysDictService.findImageServerAddress() + robotIcon;
		String now = DateUtils.getNowDateString();
		Map<String, Object> msgMap = new HashMap<>();
		Map<String, String> paraMap = new HashMap<>();
		paraMap.put("robotName", robotName);
		paraMap.put("robotIcon", robotIconUrl);
		paraMap.put("robotMessage", robotMessage);
		paraMap.put("mySendTime", now);
		paraMap.put("nowTime", now);

		// 获取机器人等级信息
		UserRankPojo userRankPojo = null;
		if(org.apache.commons.lang3.StringUtils.isNotBlank(userLv)) {
			UserRankPojo userRank = new UserRankPojo();
			userRank.setLevelno(userLv);
			userRankPojo = userRankService.getUserRank(userRank);
			paraMap.put("level_photourl",
					userRankPojo == null ? "" : sysDictService.findImageServerAddress() + userRankPojo.getLevelPhotourl());
		}
		msgMap.put("robotMessage", paraMap);
		// 写入数据库 历史记录
		ChatRecord chatRecord = new ChatRecord();
		String uuid = UUID.randomUUID().toString();
		chatRecord.setId(uuid);
		chatRecord.setRoomnumber(roomNumber);
		chatRecord.setSenderphoto(robotIcon);
		chatRecord.setSendernickname(robotName);
		chatRecord.setLevel_photourl(userRankPojo == null ? "" : userRankPojo.getLevelPhotourl());
		String[] itemMssages = robotMessage.split("\\|");
		Map<String, Object> paramMap = new HashMap<>();
		String betStr = "";
		String ballOdd = "";// 赔率
		String point = "";
		int totleAmt = 0;
		for (int j = 0; j < itemMssages.length; j++) {
			String[] str = itemMssages[j].split(",");
			String str1 = initplz(str[0]);
			if (j >= 1) {
				betStr += ",";
				ballOdd += ",";
			}
			betStr += str1; // 下的什么注
			ballOdd += str[1];
			point = str[2];
			totleAmt = Integer.parseInt(str[2]) * itemMssages.length;
		}

		paramMap.put("gameQi", gameQi);
		paramMap.put("roomId", roomNumber);
		paramMap.put("robotName", robotName);
		paramMap.put("betStr", betStr);
		paramMap.put("ballOdd", ballOdd);
		paramMap.put("point", point);
		paramMap.put("totleAmt", totleAmt);
		paramMap.put("gameId", UUIDUtils.randomUUID());
		paramMap.put("gameUserId", UUIDUtils.randomUUID());

		String orginMsg = JSON.toJSONString(paramMap);

		Map<String, String> paramMap1 = new HashMap<>();
		paramMap1.put("roomNumber", roomNumber);
		paramMap1.put("sendernickname", robotName);
		paramMap1.put("betsSend", "true");
		paramMap1.put("message", orginMsg);
		paramMap1.put("photourl", robotIcon);
		paramMap1.put("mySendTime", now);
		paramMap1.put("nowTime", now);
		// paramMap1.put("betsSend", "true");
		String msg = JSON.toJSONString(paramMap1);
		chatRecord.setMsgContent(msg);
		chatRecord.setOrginMsg(orginMsg);
		chatRecord.setSenderUserid("robot");
		chatRecord.setMessageStatus("0");
		chatRecord.setChatType("0");

		chatRecord.setTimestamp(now);

		String sendMsg = JSONObject.toJSONString(msgMap);

		Set<String> userIdList = context.getUserIdsByRoomNumber(roomNumber);
		if (!CollectionUtils.isEmpty(userIdList)) {
			userIdList.forEach(userId -> {
				// 推送消息
				webSocketService.sendToTheUser(sendMsg, userId, null, null);
				// 保存消息数据
				websocketMessageService.saveWebsocketMessage2(robotName, sendMsg, userId, roomNumber, "0",
						GameConstants.GAME_STATUS_MAINTAIN, GameConstants.WEBSOCKET_MESSAGE_STATUS_CREATE);
			});
		}
		chatRecordService.addChatRecord(chatRecord);

	}

	/**
	 * 初始化赔率
	 *
	 * @return
	 */
	public String initpl(String roomNunber, String msg) {
		String plinfo = "";
		Map<String, Object> itemMap = new HashMap<>();
		itemMap.put("大", "da_pl");
		itemMap.put("单", "dan_pl");
		itemMap.put("双", "shuang_pl");
		itemMap.put("小", "xiao_pl");
		itemMap.put("大单", "dadan_pl");
		itemMap.put("大双", "dashuang_pl");
		itemMap.put("小单", "xiaodan_pl");
		itemMap.put("小双", "xiaoshuang_pl");
		itemMap.put("极大", "jida_pl");
		itemMap.put("极小", "jixiao_pl");
		itemMap.put("红波", "hongbo_pl");
		itemMap.put("蓝波", "lanbo_pl");
		itemMap.put("绿波", "lvbo_pl");
		itemMap.put("豹子", "baizi_pl");
		itemMap.put("顺子", "shunzi_pl");
		itemMap.put("对子", "duizi_pl");
		for (int i = 0; i < 28; i++) {
			itemMap.put("特码" + i, "tema" + i + "_pl");
		}
		try {

			Map<String, Object> map = operationalSetService.queryPlInfo(roomNunber);
			if (map != null) {
				if (itemMap.containsKey(msg)) {
					if (!StringUtils.isEmpty(map.get(itemMap.get(msg)))) {
						plinfo = (String) map.get(itemMap.get(msg));
					}
				}
			}
			return plinfo;
		} catch (Exception e) {
			log.debug("初始化赔率异常:", e);
			return "";
		}
	}

	/**
	 * 获取英文赔率
	 *
	 * @return
	 */
	public String initplz(String msg) {
		String plinfo = "";
		Map<String, String> itemMap = new HashMap<>();
		itemMap.put("大", "da");
		itemMap.put("单", "dan");
		itemMap.put("双", "shuang");
		itemMap.put("小", "xiao");
		itemMap.put("大单", "dadan");
		itemMap.put("大双", "dashuang");
		itemMap.put("小单", "xiaodan");
		itemMap.put("小双", "xiaoshuang");
		itemMap.put("极大", "jida");
		itemMap.put("极小", "jixiao");
		itemMap.put("红波", "hongbo");
		itemMap.put("蓝波", "lanbo");
		itemMap.put("绿波", "lvbo");
		itemMap.put("豹子", "baozi");
		itemMap.put("顺子", "shunzi");
		itemMap.put("对子", "duizi");
		for (int i = 0; i < 28; i++) {
			itemMap.put("特码" + i, "tema" + i);
		}
		try {
			if (itemMap.containsKey(msg)) {
				plinfo = itemMap.get(msg);
			}

			return plinfo;
		} catch (Exception e) {
			log.debug("初始化赔率异常:", e);
			return "";
		}
	}

	/**
	 * 分割 机器人下注方案
	 *
	 * @param str 下注方案 大100
	 * @return
	 */
	private String[] pattern(String str) {
		List<String> list = Lists.newArrayList();
		int index = str.indexOf(RANDOM_AMOUNT_STRING);
		if (index > 0) {
			list.add(str.substring(0, index - 1));
			list.add(str.substring(index, str.length() - 1));
		} else {
			Matcher m = pattern.matcher(str);
			while (m.find()) {
				list.add(m.group());
			}
		}
		return list.toArray(new String[0]);
	}

	public static void main(String[] args) {
		RobotSpeakExecutor speak = new RobotSpeakExecutor();
		String[] temp = speak.pattern("大{随机金额1}");
		for (String s : temp) {
			System.out.println(s);
		}
	}

}
